/*
 * Copyright 2008-2009 Aying.Net Powered by Fuchun.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.aying.util;

import java.util.List; // import java.util.Iterator;
import java.util.LinkedList;
import java.math.BigDecimal;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.aying.util.security.Crypto;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.gson.reflect.TypeToken;

/**
 * 包含 {@code Servlet} 常用方法的便捷工具类。
 * 
 * @author Fuchun
 * @version 1.0, 2009-06-14
 */
public class ServletUtils extends Utils {

	private static final String UNKNOWN_IP = "unknown";

	private static final Log log = LogFactory.getLog(ServletUtils.class);

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 若该参数没被传递或没被赋值时返回空字符串（&quot;&quot;）。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的参数的值。
	 * @see #getParameter(HttpServletRequest, String, String)
	 */
	public static String getParameter(HttpServletRequest request, String name) {
		return getParameter(request, name, StringUtils.EMPTY);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static String getParameter(HttpServletRequest request, String name, String defaultValue) {
		if (!StringUtils.hasText(name))
			return defaultValue;
		String value = request.getParameter(name);
		return value == null ? defaultValue : value.trim();
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 该参数所获得的值是一个数组，相当于接收的是 {@code CheckBox} 或者 {@code ComboBox} 的值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static String[] getParameters(HttpServletRequest request, String name) {
		return getParameters(request, name, new String[] {});
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 该参数所获得的值是一个数组，相当于接收的是 {@code CheckBox} 或者 {@code ComboBox} 的值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaults 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static String[] getParameters(HttpServletRequest request, String name, String[] defaults) {
		if (!StringUtils.hasText(name))
			return defaults;
		String[] values = request.getParameterValues(name);
		return values == null || values.length == 0 ? defaults : values;
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。 该参数所获得的值是一组
	 * {@code java.util.List&lt;String&gt;} 封装的值，相当于接收的是 {@code CheckBox} 或者 {@code
	 * ComboBox} 的值。若该参数没被传递或没被赋值时返回 0 长度的 {@code java.util.List&lt;String&gt;}。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static List<String> getParametersByList(HttpServletRequest request, String name) {
		return getParametersByList(request, name, new LinkedList<String>());
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。 该参数所获得的值是一组
	 * {@code java.util.List&lt;String&gt;} 封装的值，相当于接收的是 {@code CheckBox} 或者 {@code
	 * ComboBox} 的值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultList 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static List<String> getParametersByList(HttpServletRequest request, String name, List<String> defaultList) {
		if (!StringUtils.hasText(name))
			return defaultList;
		String[] values = request.getParameterValues(name);
		if (values == null || values.length == 0)
			return defaultList;
		else {
			List<String> list = new LinkedList<String>();
			for (String val : values) {
				list.add(val);
			}
			return list;
		}
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code
	 * java.math.BigDecimal} 类型的参数值。 若该参数没被传递或没被赋值时返回 {@code java.math.BigDecimal} 类型的 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code java.math.BigDecimal} 类型的参数值
	 * @see #getBigDecimalParameter(HttpServletRequest, String, BigDecimal)
	 */
	public static BigDecimal getBigDecimalParameter(HttpServletRequest request, String name) {
		return getBigDecimalParameter(request, name, NumberUtils.parseDecimal("0"));
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code
	 * java.math.BigDecimal} 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code java.math.BigDecimal} 类型的参数值
	 */
	public static BigDecimal getBigDecimalParameter(HttpServletRequest request, String name, BigDecimal defaultValue) {
		return NumberUtils.parseDecimal(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的布尔值。
	 * 若该参数没被传递或没被赋值时默认返回 {@code false}。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的布尔值。
	 * @see #getBoolParameter(HttpServletRequest, String, boolean)
	 */
	public static boolean getBoolParameter(HttpServletRequest request, String name) {
		return getBoolParameter(request, name, Boolean.FALSE);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的布尔值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的布尔值。
	 */
	public static boolean getBoolParameter(HttpServletRequest request, String name, boolean defaultValue) {
		String value = getParameter(request, name).trim();
		if (!StringUtils.hasText(value))
			return defaultValue;
		if (TRUE.equals(value) || ON.equals(value) || FLAG_TRUE.equals(value))
			return Boolean.TRUE;
		else if (FALSE.equals(value) || OFF.equals(value) || FLAG_FALSE.equals(value))
			return Boolean.FALSE;
		return defaultValue;
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code byte}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code byte} 类型的 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code byte} 类型的参数值
	 * @see #getByteParameter(HttpServletRequest, String, byte)
	 */
	public static byte getByteParameter(HttpServletRequest request, String name) {
		return getByteParameter(request, name, (byte) 0);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code byte} 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code byte} 类型的参数值
	 */
	public static byte getByteParameter(HttpServletRequest request, String name, byte defaultValue) {
		return NumberUtils.parseByte(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code double}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code double} 类型的 0.0d。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code double} 类型的参数值
	 * @see #getDoubleParameter(HttpServletRequest, String, double)
	 */
	public static double getDoubleParameter(HttpServletRequest request, String name) {
		return getDoubleParameter(request, name, 0.0d);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code double}
	 * 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code double} 类型的参数值
	 */
	public static double getDoubleParameter(HttpServletRequest request, String name, double defaultValue) {
		return NumberUtils.parseDouble(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code float}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code float} 类型的 0.0f。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code float} 类型的参数值
	 * @see #getFloatParameter(HttpServletRequest, String, float)
	 */
	public static float getFloatParameter(HttpServletRequest request, String name) {
		return getFloatParameter(request, name, 0.0f);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code float} 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code float} 类型的参数值
	 */
	public static float getFloatParameter(HttpServletRequest request, String name, float defaultValue) {
		return NumberUtils.parseFloat(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code int}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code int} 类型的 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code int} 类型的参数值
	 * @see #getIntParameter(HttpServletRequest, String, int)
	 */
	public static int getIntParameter(HttpServletRequest request, String name) {
		return getIntParameter(request, name, 0);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code int} 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code int} 类型的参数值
	 */
	public static int getIntParameter(HttpServletRequest request, String name, int defaultValue) {
		return NumberUtils.parseInt(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code long}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code long} 类型的 0L。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code long} 类型的参数值
	 * @see #getLongParameter(HttpServletRequest, String, long)
	 */
	public static long getLongParameter(HttpServletRequest request, String name) {
		return getLongParameter(request, name, 0L);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code long} 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code long} 类型的参数值
	 */
	public static long getLongParameter(HttpServletRequest request, String name, long defaultValue) {
		return NumberUtils.parseLong(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code short}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code short} 类型的 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code short} 类型的参数值
	 * @see #getShortParameter(HttpServletRequest, String, short)
	 */
	public static short getShortParameter(HttpServletRequest request, String name) {
		return getShortParameter(request, name, (short) 0);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code short} 类型的参数值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code short} 类型的参数值
	 */
	public static short getShortParameter(HttpServletRequest request, String name, short defaultValue) {
		return NumberUtils.parseShort(getParameter(request, name), defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回空字符串（&quot;&quot;）。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static String getAttribute(HttpServletRequest request, String name) {
		return getAttribute(request, name, StringUtils.EMPTY);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static String getAttribute(HttpServletRequest request, String name, String defaultValue) {
		if (!StringUtils.hasText(name))
			return defaultValue;
		try {
			String value = (String) request.getAttribute(name);
			if (value == null) {
				value = (String) request.getSession().getAttribute(name);
			}
			return value;
		} catch (Exception ex) {
			return defaultValue;
		}
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static int getIntAttribute(HttpServletRequest request, String name) {
		return getIntAttribute(request, name, 0);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static int getIntAttribute(HttpServletRequest request, String name, int defaultValue) {
		if (!StringUtils.hasText(name))
			return defaultValue;
		return NumberUtils.parseInt(getAttribute(request, name), defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static long getLongAttribute(HttpServletRequest request, String name) {
		return getLongAttribute(request, name, 0L);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static long getLongAttribute(HttpServletRequest request, String name, long defaultValue) {
		if (!StringUtils.hasText(name))
			return defaultValue;
		return NumberUtils.parseLong(getAttribute(request, name), defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回 0。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static short getShortAttribute(HttpServletRequest request, String name) {
		return getShortAttribute(request, name, (short) 0);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static short getShortAttribute(HttpServletRequest request, String name, short defaultValue) {
		if (!StringUtils.hasText(name))
			return defaultValue;
		return NumberUtils.parseShort(getAttribute(request, name), defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static List<String> getListAttribute(HttpServletRequest request, String name, List<String> defaultValue) {
		return getAttribute(request, name, new TypeToken<List<String>>() {
		}, defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 中或者在 {@code
	 * javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。属性值的类型由 {@code
	 * clazz} 指定。
	 * 
	 * @param <T> 指定要转换的属性值类型。
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param type 要从 {@code HttpServletRequest} 请求对象中获得的属性的类型。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getAttribute(HttpServletRequest request, String name, TypeToken<T> type, T defaultValue) {
		long start = System.currentTimeMillis();
		if (!StringUtils.hasText(name))
			return defaultValue;
		Object val = request.getAttribute(name);
		if (val == null) {
			HttpSession session = request.getSession();
			if (session != null)
				val = session.getAttribute(name);
		}
		if (val == null)
			val = defaultValue;
		T result = null;
		try {
			result = ((Class<T>) type.getRawType()).cast(val);
		} catch (ClassCastException e) {
			log.warn("类型 " + type.getRawType().getName() + " 转换错误！");
			result = defaultValue;
		}
		log.debug("getAttribute(HttpServletRequest, String, TypeClass<T>, T) \n" + "(类型：" + type.getRawType().getName()
				+ ")方法执行时间 " + (System.currentTimeMillis() - start));
		return result;
	}

	/**
	 * 重新获得在 {@code HttpServletRequest} 或 {@code Cookie} 中保存的值。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param key 给定的键。
	 * @param isDecrypt 取出的值是否要解密。
	 * @return 在 {@code HttpServletRequest} 或 {@code Cookie} 中保存的值。
	 */
	public static String retrieve(HttpServletRequest request, HttpServletResponse response, String key,
			boolean... isDecrypt) {
		String value = (String) request.getAttribute(key);
		if (!StringUtils.hasText(value) || "null".equalsIgnoreCase(value)) {
			value = getCookieValue(request, key, isDecrypt);
		}
		return value;
	}

	/**
	 * 在 {@code HttpServletRequest} 或 {@code Cookie} 中保存给定的键值对。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的值的唯一名称。
	 * @param value 保存的对应于名称的值。
	 * @param domains 保存 {@code Cookie} 时指定的一个或一组域。
	 */
	public static void store(HttpServletRequest request, HttpServletResponse response, String name, String value,
			String... domains) {
		store(request, response, name, value, 0, domains);
	}

	/**
	 * 在 {@code HttpServletRequest} 中保存给定的键值对，若给定的保存周期 {@code storeTime} 大于0， 则同时保存到客户端
	 * {@code Cookie} 中。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的值的唯一名称。
	 * @param value 保存的对应于名称的值。
	 * @param saveTime 存入 {@code Cookie} 的周期，单位：秒(s)。
	 * @param domains 保存 {@code Cookie} 时指定的一个或一组域。
	 */
	public static void store(HttpServletRequest request, HttpServletResponse response, String name, String value,
			int saveTime, String... domains) {
		if (!StringUtils.hasText(name)) {
			return;
		}
		request.setAttribute(name, value);
		if (saveTime > 0) { // 需要保存到Cookie中
			if (isNotEmpty(domains)) {
				for (String domain : domains) {
					saveCookie(response, name, value, saveTime, domain);
				}
			}
		}
	}

	/**
	 * 删除存储的值，该值可能保存于 {@code HttpServletRequest} 或 {@code Cookie} 中。 若要删除的给定键 {@code name}
	 * 为空，则不作任何处理。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 要删除的值的给定键。
	 * @param domains {@code Cookie} 值保存的域，该域可能存在多个。
	 */
	public static void delete(HttpServletRequest request, HttpServletResponse response, String name, String... domains) {
		if (!StringUtils.hasText(name))
			return;
		request.removeAttribute(name);
		// 删除所有有关域下的给定键的值。
		if (domains != null && domains.length > 0) {
			for (String domain : domains) {
				deleteCookie(response, name, domain);
			}
		}
	}

	/**
	 * 删除给定键的 {@code Cookie} 值。{@code name} 为 {@code null} 或者空字符串，则不作任何操作。
	 * 
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 要删除的 {@code Cookie} 键名。
	 */
	public static void deleteCookie(HttpServletResponse response, String name, String domain) {
		Cookie cookie = new Cookie(name, StringUtils.EMPTY);
		// 当用户关闭浏览器时删除Cookie的值
		if (StringUtils.hasText(domain))
			cookie.setDomain(domain);
		cookie.setMaxAge(-1);
		cookie.setPath("/");
		response.addCookie(cookie);
	}

	/**
	 * 在客户端 {@code Cookie} 中保存给定的键值对，保存的值的周期由 {@code saveTime} 指定，单位：秒(s)。 默认的保存周期为一小时。
	 * 
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的 {@code Cookie} 的值的唯一名称。
	 * @param value 存的 {@code Cookie} 的对应于名称的值。
	 * @param domain {@code Cookie} 保存的域。
	 * @param isEncrypt 是否用默认的加密/解密方式加密 {@code Cookie} 的值。
	 */
	public static void saveCookie(HttpServletResponse response, String name, String value, String domain,
			boolean... isEncrypt) {
		saveCookie(response, name, value, 60 * 60, domain, isEncrypt);
	}

	/**
	 * 在客户端 {@code Cookie} 中保存给定的键值对，保存的值的周期由 {@code saveTime} 指定，单位：秒(s)。
	 * 
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的 {@code Cookie} 的值的唯一名称。
	 * @param value 保存的 {@code Cookie} 的对应于名称的值。
	 * @param saveTime {@code Cookie} 保存的周期(单位：秒) -1 - 关闭浏览器即失效。
	 * @param domain {@code Cookie} 保存的域。
	 * @param isEncrypt 是否用默认的加密/解密方式加密 {@code Cookie} 的值。
	 */
	public static void saveCookie(HttpServletResponse response, String name, String value, int saveTime, String domain,
			boolean... isEncrypt) {
		if (value == null)
			value = StringUtils.EMPTY;
		if (isEncrypt != null && isEncrypt.length > 0) {
			if (isEncrypt[0])
				value = encryptCookie(value);
		}
		Cookie cookie = new Cookie(name, value);
		cookie.setDomain(domain);
		cookie.setMaxAge(saveTime);
		cookie.setPath("/");
		cookie.setSecure(false);
		response.addCookie(cookie);
	}

	/**
	 * 保存一组给定的 {@code Cookie}。
	 * <ul>
	 * <li>若其中 {@code Cookie} 中的 {@code name} 和 {@code value} 属性为空，则该项 {@code Cookie}
	 * 不会进行保存；</li>
	 * <li>若其中 {@code Cookie} 中的 {@code path} 属性为空，则默认为 &quot;/&quot;；</li>
	 * <li>若其中 {@code Cookie} 中的 {@code secure} 属性为 {@code true}，则只能在 {@code HTTPS}
	 * 下才能发送保存；</li>
	 * </ul>
	 * 
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param cookies 要保存的一组 {@code Cookie}。
	 */
	public static void saveCookies(HttpServletResponse response, List<Cookie> cookies) {
		if (isEmpty(cookies)) {
			log.warn("要保存的 cookies(List<Cookie>) 是空的！");
			return;
		}
		StringBuilder warnMessages = new StringBuilder();
		for (int i = 0, len = cookies.size(); i < len; i++) {
			Cookie c = cookies.get(i);
			if (c != null && !StringUtils.isNullOrEmpty(c.getName()) && !StringUtils.isNullOrEmpty(c.getValue())) {
				if (StringUtils.isNullOrEmpty(c.getPath()))
					c.setPath("/");
				response.addCookie(c);
			} else {
				warnMessages.append("\ncookies(List<Cookie>) 中索引为 ");
				warnMessages.append(i).append(" 的 Cookie 未设置 name 或者 value，保存失败！");
			}
		}
		if (warnMessages.length() > 0) {
			if (log.isWarnEnabled())
				log.warn(warnMessages.toString());
		}
	}

	/**
	 * 保存一组给定的 {@code Cookie}。具体请参见 {@link #saveCookies(HttpServletResponse, List)}。
	 * 
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param cookies 要保存的一组 {@code Cookie}。
	 */
	public static void saveCookies(HttpServletResponse response, Cookie... cookies) {
		if (cookies != null && cookies.length > 0) {
			List<Cookie> cookieList = new LinkedList<Cookie>();
			for (Cookie c : cookies) {
				cookieList.add(c);
			}
			saveCookies(response, cookieList);
		}
	}

	/**
	 * 获取给定键的 {@code Cookie} 值。若给定的 {@code Cookie} 的 {@code name} 不存在， 则返回 {@code null}。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 给定的 {@code Cookie} 的键值。
	 * @param isDecrypt 取出的值是否要解密。
	 * @return 返回给定键的 {@code Cookie} 值。
	 */
	public static String getCookieValue(HttpServletRequest request, String name, boolean... isDecrypt) {
		Cookie cookie = getCookie(request, name);
		if (cookie == null)
			return null;
		String value = cookie.getValue();
		if (isDecrypt != null && isDecrypt.length > 0 && isDecrypt[0]) {
			value = decryptCookie(value);
		}
		return value;
	}

	/**
	 * 使用给定的算法加密一段字符串。若要加密的字符串为 {@code null}，则返回 {@code null}。
	 * <p>
	 * <strong>注意：空字符串（&quot;&quot;）也能被加密</strong>
	 * </p>
	 * 
	 * @param plaintext 要加密的字符串。
	 * @return 返回给定字符串的加密密文。
	 */
	public static String encryptCookie(String plaintext) {
		if (plaintext == null)
			return null;
		Crypto crypto = Crypto.getInstance(Crypto.DEFAULT_KEY_SPEC_STRING, Crypto.DES_ALGORITHM);
		if (crypto == null) {
			return null;
		}
		return crypto.encrypt(plaintext);
	}

	/**
	 * 使用给定的算法解密一段密文字符串。若要解密的字符串为 {@code null} 或空字符串，则返回 {@code null}。
	 * <p>
	 * <strong>注意：只要返回的字符串不为 {@code null}，则表示解密成功。因为该方法不会抛出任何的异常。</strong>
	 * </p>
	 * 
	 * @param encrypttext 要解密的密文字符串。
	 * @return 返回给定密文字符串的原生字符串。
	 */
	public static String decryptCookie(String encrypttext) {
		if (!StringUtils.hasText(encrypttext))
			return null;
		Crypto crypto = Crypto.getInstance(Crypto.DEFAULT_KEY_SPEC_STRING, Crypto.DES_ALGORITHM);
		if (crypto == null) {
			return null;
		}
		return crypto.decrypt(encrypttext);
	}

	/**
	 * 获取给定键值的 {@code Cookie}。若给定的 {@code Cookie} 键不存在，则返回 {@code null}。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 给定的 {@code Cookie} 的键值。
	 * @return 返回给定键的 {@code Cookie} 对象。
	 */
	public static Cookie getCookie(HttpServletRequest request, String name) {
		Cookie[] cookies = request.getCookies(); // 获得Cookie的集合
		if (cookies == null || !StringUtils.hasText(name))
			return null;
		for (int i = 0; i < cookies.length; i++) {
			if (name.equals(cookies[i].getName())) {
				return cookies[i];
			}
		}
		return null;
	}

	/**
	 * 获取当前Http请求的客户端的真实IP。若取不到IP值，则返回空字符串（&quot;&quot;）。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @return 当前Http请求的客户端的真实IP串。
	 */
	public static String getClientIp(HttpServletRequest request) {
		if (request == null)
			return StringUtils.EMPTY;
		String ip = request.getHeader("X-Forwarded-For");
		if (StringUtils.isNullOrEmpty(ip) || UNKNOWN_IP.equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (StringUtils.isNullOrEmpty(ip) || UNKNOWN_IP.equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (StringUtils.isNullOrEmpty(ip) || UNKNOWN_IP.equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (StringUtils.isNullOrEmpty(ip) || UNKNOWN_IP.equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (StringUtils.isNullOrEmpty(ip) || UNKNOWN_IP.equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	/**
	 * 获取当前Http请求的客户端的真实IP。若取不到IP值，则返回空字符串（&quot;&quot;）。 该方法与
	 * {@link #getIp(HttpServletRequest)} 方法效果相同。
	 * 
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @return 当前Http请求的客户端的真实IP串。
	 */
	public static String getIp(HttpServletRequest request) {
		return getClientIp(request);
	}
}
